#include "ClientConnection.h"

using namespace std;
using namespace network;

bool ClientConnection::connect(Address address) {
    int ret = ::connect(fd_, address.getSockAddr(), sizeof(*address.getSockAddr()));
    return connected_ = (ret == 0);
}

std::string ClientConnection::read() {
    std::string tmp = read_buffer_;
    read_buffer_.clear();
    return tmp;
}

void ClientConnection::send(const std::string &data) {
    if (!connected_) throw runtime_error("client not connected");
    write_buffer_.append(data);
    reactor_->addEvent(fd_, EventType::Write);
}

void ClientConnection::disconnect() const {
    if (connected_) {
        reactor_->addEvent(fd_, EventType::Close);
    }
}

#if defined(WIN32) || defined(_WIN32)

void ClientConnection::clientRecv() {
    std::string message;
    char read_buffer[1024] = {0};
    size_t read_buffer_size = 1024, read_len = 0;
    while (true) {
        read_len = ::recv(fd_, read_buffer, read_buffer_size, 0);
        if (read_len == 0) {
            disconnect();
            break;
        } else if (read_len == SOCKET_ERROR) {
            int error = WSAGetLastError();
            if (error == WSAEWOULDBLOCK) {
                if (message.empty()) {
                    break;
                }
                read_buffer_ = message;
                if (recv_cb_ != nullptr) {
                    recv_cb_(this);
                }
                break;
            } else if (error == WSAEINTR) {
                continue;// 来自系统内部中断，重试recv即可
            } else {
                message.clear();// 读数据出现异常了，清空读缓冲区并退出即可
                break;
            }
        } else {
            message.append(read_buffer, read_len);
        }
    }
}

#else

void ClientConnection::clientRecv() {
    std::string message;
    char read_buffer[1024] = {0};
    size_t read_buffer_size = 1024, read_len = 0;
    while (true) {
        read_len = ::recv(fd_, read_buffer, read_buffer_size, 0);
        if (read_len == 0) {
            disconnect();
            break;
        }
        else if (read_len == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                read_buffer_ = message;
                if (recv_cb_ != nullptr) {
                    recv_cb_(this);
                }
                break;
            }
            else if (errno == EINTR) {
                continue; // 来自系统内部中断，重试recv即可
            }
            else {
                message.clear(); // 读数据出现异常了，清空读缓冲区并退出即可
                break;
            }
        }
        else {
            message.append(read_buffer, read_len);
        }
    }
}

#endif

void ClientConnection::clientSend() {
    char *send_buffer = &write_buffer_[0];
    size_t total_size = write_buffer_.size();
    ssize_t send_len = 0, ret = 0;
    while (total_size > send_len) {
        ret = ::send(fd_, send_buffer + send_len, total_size, 0);
        if (ret == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                break;
            }
            disconnect();
            return;
        }
        send_len += ret;
    }
    if (total_size > send_len) {
        write_buffer_.erase(0, send_len);
        reactor_->changeEventType(fd_, EventType::Write);
    }
    else {
        write_buffer_.clear();
        reactor_->changeEventType(fd_, EventType::Read);
    }
}

void ClientConnection::clientClose() {
    if (close_cb_ != nullptr) {
        close_cb_(this);
    }
    connected_ = false;
    reactor_->removeHandler(fd_);
    closeFd();
}
